[bits 32]
global asm_hello_world
global asm_lidt
global asm_unhandled_interrupt
global asm_halt
global asm_out_port
global asm_in_port
global asm_time_interrupt_handler
global asm_keyboard_interrupt_handler
global asm_enable_interrupt
global asm_disable_interrupt
global asm_interrupt_status
global asm_switch_thread
global asm_atomic_exchange
global asm_init_page_reg

extern c_time_interrupt_handler
extern c_keyboard_interrupt_handler

ASM_IDTR dw 0
	     dd 0
ASM_UNHANDLED_INTERRUPT_INFO db "Unhandled interrupt happened,halt..."
			                 db 0     
string db "22336271 ysj,dear,I'm your operating system!Thank you:)"
string_end:


asm_hello_world:
    push eax
    push ebx
    push ecx
    push esi
    ;输出标签
    mov ecx,string_end - string
    mov ebx,(80*10+10)*2 ;(10,10)
    mov esi,string
    mov ah,0x5b		;背景红 字体青色
    output_string:
        mov al,[esi]
        mov word[gs:ebx],ax
        add ebx,2
        inc esi
        loop output_string
    pop esi
    pop ecx
    pop ebx
    pop eax
    ret

;void asm_lidt(uint32 start,uint16 limit)IDT的基地址和表界限
asm_lidt:
    push ebp
    mov ebp,esp
    push eax
    
    mov eax,[ebp+4*3]		;注意栈有哪些元素，[ebp+4*2]是函数第一个参数位置，此处应该是3个双字dd
    mov [ASM_IDTR],ax
    mov eax,[ebp+4*2]
    mov [ASM_IDTR+2],eax
    lidt [ASM_IDTR]
    
    pop eax
    pop ebp
    ret
;void asm_unhandled_interrupt()
asm_unhandled_interrupt:
    cli
    mov esi,ASM_UNHANDLED_INTERRUPT_INFO
    xor ebx,ebx
    mov ah,0x04
    .output_information:
        cmp byte[esi],0
        je .end
        mov al,byte[esi]
        mov word[gs:bx],ax
        inc esi
        add ebx,2
        jmp .output_information
    .end:
    jmp $
asm_halt:
    jmp $

;void asm_out_port(uint16 port,uint8 value)
    asm_out_port:
    push ebp
    mov ebp,esp
    push edx
    push eax

    mov edx,[ebp+4*2];port
    mov eax,[ebp+4*3];value
    out dx,al

    pop eax
    pop edx
    pop ebp
    ret

;void asm_in_port(uint16 port,uint8* value)
asm_in_port:
    push ebp
    mov ebp,esp
    push edx
    push eax
    push ebx

    xor eax,eax
    mov edx,[ebp+4*2]   ;port
    mov ebx,[ebp+4*3]   ;*value

    in al,dx
    mov [ebx],al

    pop ebx
    pop eax
    pop edx
    pop ebp
    ret

asm_time_interrupt_handler:
    pushad

    ;发送EOI消息，否则下一次中断不发生
    mov al,0x20
    out 0x20,al
    out 0xa0,al
    
    call c_time_interrupt_handler

    popad
    iret
asm_keyboard_interrupt_handler:
    pushad

    ;发送EOI消息，否则下一次中断不发生
    mov al,0x20
    out 0x20,al
    out 0xa0,al

    mov al,0x61
    out 0x20,al
    in al,0x60
    push eax
    call c_keyboard_interrupt_handler
    add esp,4

    popad
    iret
;void asm_enable_interrupt();
asm_enable_interrupt:
    sti
    ret
;void asm_disable_interrupt();
asm_disable_interrupt:
    cli
    ret
;int asm_interrupt_status();
asm_interrupt_status:
    xor eax,eax
    pushfd
    pop eax
    and eax,0x200
    ret
;void asm_switch_thread(PCB* cur,PCB* next);
asm_switch_thread:
    push ebp
    push ebx
    push edi
    push esi

    mov eax,[esp+5*4]
    mov [eax],esp   ;保存当前栈指针到PCB，以便后续恢复

    mov eax,[esp+6*4]
    mov esp,[eax]   ;此时栈已经从cur切换到next

    pop esi
    pop edi
    pop ebx
    pop ebp
    sti 
    ret
;void asm_atomic_exchange(uint32* reg,uint32* mem);
asm_atomic_exchange:
    push ebp
    mov ebp,esp
    pushad

    ;1.当reg不为共享变量才是原子指令
    ; mov ebx,[ebp+4*2]   ;reg
    ; mov eax,[ebx]       ;取出reg值
    ; mov ebx,[ebp+4*3]   ;mem
    ; xchg [ebx],eax      ;原子交换指令
    ;;lock cmpxchg [ebx],eax    ;2.
    ; mov ebx,[ebp+4*2]   ;mem
    ; mov [ebx],eax       ;将mem值赋给reg指向的变量
    

    ;3.分别对mem设为1，reg设为0
    mov eax,[ebp+4*2]   ;reg
    mov ebx,[eax]       ;取出reg值
    mov ecx,[ebp+4*3]   ;mem
    retry:
    lock bts dword [ecx],0  ;mem设置第0位为1
    jnc retry               ;cf!=1则重新设置,如果本来就是1则设置失败
    btr dword [eax],0       ;reg设置0

    popad
    pop ebp
    ret
;void asm_init_page_reg(int* directory);
asm_init_page_reg:
    push ebp
    mov ebp,esp
    push eax

    mov eax,[ebp+4*2]
    mov cr3,eax     ;放入页目录表地址
    mov eax,cr0     
    or eax,0x80000000
    mov cr0,eax     ;置PG=1,开启分页机制

    pop eax
    pop ebp
    ret

